package oneD.fem.structure;

import inf.jlinalg.GeneralMatrixLSESolver;
import inf.jlinalg.ILSESolver;
import inf.jlinalg.IMatrix;
import inf.jlinalg.QuadraticMatrixInfo;
import inf.jlinalg.SolveFailedException;

public class Truss extends Structure {
	public Truss() {

	}

	public void addElement(double rho, double e, double a, int n1, int n2) {
		this.elements_.add(new oneD.fem.element.linear.Truss(rho, e, a,
				this.nodes_.get(n1), this.nodes_.get(n2)));
	}

	@Override
	public void printStructure() {
		super.printStructure();
		System.out.println("Elements:");
		System.out.println("idx\tE\tA\tlength");
		for (int i = 0; i < this.getNumberOfElements(); i++) {
			System.out.print(i + "\t");
			this.elements_.get(i).print();
			System.out.println();
		}
	}

	@Override
	public void solve() {
		/*
		 * solve Ku=F
		 */
		int NEQ = this.enumerateDOFs();
		// solver initialization
		ILSESolver solver = new GeneralMatrixLSESolver(
				GeneralMatrixLSESolver.SOLVER_IMPL_JAVA);
		// ILSESolver solver = new GeneralMatrixLSESolver();
		// ILSESolver solver = new SpoolesLSESolver();
		// using this for solver implementation in Java, it will be slow
		QuadraticMatrixInfo aInfo = solver.getAInfo();
		IMatrix kGlobal = solver.getA();
		double[] rGlobal = new double[NEQ];

		aInfo.setSize(NEQ);
		solver.initialize();

		this.assembleStiffnessMatrix(kGlobal, true);
		this.assembleLoadVector(rGlobal);

		// System.out.println("System stiffness matrix:");
		// System.out.println(MatrixFormat.format(kGlobal));

		// solve the system of equation
		try {
			solver.solve(rGlobal);
		} catch (SolveFailedException e) {
			System.out.println("Solver failed: " + e.getMessage());
		}
		// System.out.println("Solution x:");
		// System.out.println(ArrayFormat.format(rGlobal));

		// pass the result back to nodes
		this.setDisplacement(rGlobal);
	}

	@Override
	public void assembleLoadVector(double[] rGlobal) {
		for (int i = 0; i < this.getNumberOfNodes(); i++) {
			if (this.nodes_.get(i).getForce() != null) {
				int[] dofNumbers = this.nodes_.get(i).getDOFNumbers();
				for (int j = 0; j < 3; j++)
					if (dofNumbers[j] != -1)
						rGlobal[dofNumbers[j]] = this.nodes_.get(i).getForce()
								.getComponent(j);
			}
		}

		/*
		 * for (int i = 0; i < this.getNumberOfElements(); i++) { IVector rie =
		 * new ArrayVector(6); if (this.getElement(i).getNode(0).getForce() !=
		 * null) for (int j = 0; j < 3; j++) rie.set(j,
		 * this.getElement(i).getNode(0).getForce() .getComponent(j)); if
		 * (this.getElement(i).getNode(1).getForce() != null) for (int j = 0; j
		 * < 3; j++) rie.set(j + 3, this.getElement(i).getNode(1).getForce()
		 * .getComponent(j)); int[] dofNumbers =
		 * this.elements_.get(i).getDOFNumbers(); // assemble the internal force
		 * vector to global internal force // vector for (int j = 0; j <
		 * dofNumbers.length; j++) if (dofNumbers[j] != -1)
		 * rGlobal[dofNumbers[j]] = rie.get(j); }
		 */
	}

	@Override
	public void assembleStiffnessMatrix(IMatrix kGlobal, boolean full) {
		for (int i = 0; i < this.getNumberOfElements(); i++) {
			IMatrix ke = this.elements_.get(i).computeStiffnessMatrix();
			int[] dofNumbers = this.elements_.get(i).getDOFNumbers();
			for (int p = 0; p < 6; p++)
				for (int q = full ? 0 : p; q < 6; q++)
					if (dofNumbers[p] != -1 && dofNumbers[q] != -1)
						kGlobal.add(dofNumbers[p], dofNumbers[q], ke.get(p, q));
		}
	}

	@Override
	public void assembleMassMatrix(IMatrix mGlobal) {
		for (int i = 0; i < this.getNumberOfElements(); i++) {
			IMatrix me = this.elements_.get(i).computeMassMatrix();
			int[] dofNumbers = this.elements_.get(i).getDOFNumbers();
			for (int p = 0; p < 6; p++)
				for (int q = 0; q < 6; q++)
					if (dofNumbers[p] != -1 && dofNumbers[q] != -1)
						mGlobal.add(dofNumbers[p], dofNumbers[q], me.get(p, q));
		}
	}

	public void printDisplacement() {
		System.out.println("Displacements:");
		System.out.println("node\t\tu1\t\tu2\t\tu3");
		for (int i = 0; i < this.getNumberOfNodes(); i++) {
			System.out.print(i + "\t");
			this.nodes_.get(i).printDisplacement();
			System.out.println();
		}
	}

	@Override
	public void printResults() {
		System.out.println("Listing analysis results\n");
		this.printDisplacement();
		System.out.println("Element forces:");
		for (int i = 0; i < this.getNumberOfElements(); i++) {
			System.out.print(i + "\t" + this.elements_.get(i).computeForce());
			System.out.println();
		}
	}
}
